package org.outlook.apps.goal.pojo;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public abstract class BaseMapping<E> implements Mapping<E> {

	protected Column[] columns;
	private Map<String, String> map;

	@Override
	public Column[] getColumns() {
		return columns;
	}

	@Override
	@SuppressWarnings("unchecked")
	public E mapping(Map<String, Object> row, Class clazz) {
		try {
			Map<String, String> columnNameMaping = getColumnNameMaping();
			Object instance;
			instance = clazz.getConstructor(new Class[] {}).newInstance(new Object[] {});
			Field[] fields = clazz.getDeclaredFields();
			Method[] methods = clazz.getDeclaredMethods();
			for(Field field : fields) {
				final String fieldName = field.getName();
				String columnName = columnNameMaping.get(fieldName);
				if(row.get(columnName) != null) {
					Method method  = getSetter(methods, fieldName);
					try {
						method.invoke(instance, row.get(columnName));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
			return (E) instance;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} finally {
			
		}
		return null;
	}

	/**
	 * key:field in Class, value:field in Table
	 * @return
	 */
	private Map<String, String> getColumnNameMaping() {
		if(map == null) {
			return (map = getColumnNameMaping(columns));
		}
		return map;
	}

	public static Map<String, String> getColumnNameMaping(Column[] columns) {
		Map<String, String> map = new HashMap<String, String>(columns.length);
		for(Column column:columns)
			map.put(column.getAttribute(), column.getName());
		return map;
	}

	private Method getSetter(Method[] methods, String fieldName) {
		String methodName = getSetterMethodName(fieldName);
		for(Method method : methods) 
			if(method.getName().equals(methodName))
				return method;
		return null;
	}

	private String getSetterMethodName(String fieldName) {
		final char firsetChar = fieldName.charAt(0);
		return "set"+Character.toUpperCase(firsetChar)+fieldName.substring(1);
	}

}
